/*
	Distance.cpp
	Christopher Raffaele
	04.28.2008

	Distance's class definitions
*/
#include"DistanceConverter.h" //Distance class declarations

using namespace std;

//creates the conversion table and unit string array
DistanceConverter::DistanceConverter(){
	//allocate memory for the conversion table
	conversionTable = new double*[6];

	for(int i = 0; i < 6; ++i)
		conversionTable[i] = new double[6];

	createConversionTable();

	//allocate memory for the units string
	units = new string[6];

	createUnitsString();
}

//deallocates dynamic memory used in the table and unit string array
DistanceConverter::~DistanceConverter(){
	//delete the conversion table
	for(int i = 0; i < 6; ++i)
		delete [] conversionTable[i];

	delete [] conversionTable;
	delete [] units;
}

//display the first menu
void DistanceConverter::showMainMenu(){
	std::cout << "\n--------------------------------\n"
		 << "\\     Distance                  \\\n"
		 << " ---------------------------------\n"
		 << " | 1 | Feet                      |\n"
		 << " ---------------------------------\n"
		 << " | 2 | Inches                    |\n"
		 << " ---------------------------------\n"
		 << " | 3 | Miles                     |\n"
		 << " ---------------------------------\n"
 		 << " | 4 | Millimeters               |\n"
		 << " ---------------------------------\n"
 		 << " | 5 | Meters                    |\n"
		 << " ---------------------------------\n"
 		 << " | 6 | Centimeters               |\n"
		 << " ---------------------------------\n";
}

//create the table used to calculate conversions
void DistanceConverter::createConversionTable(){
	setFeetRow();
	setInchesRow();
	setMilesRow();
	setMillimetersRow();
	setMetersRow();
	setCentimetersRow();
};

//set the values for conversions involving feet
void DistanceConverter::setFeetRow(){
	conversionTable[0][0] = 1.0;
	conversionTable[0][1] = 12.0;
	conversionTable[0][2] = 0.00018939393939394;
	conversionTable[0][3] = 304.8;
	conversionTable[0][4] = 0.3048;
	conversionTable[0][5] = 30.48;
}

//set the values for conversions involving inches
void DistanceConverter::setInchesRow(){
	conversionTable[1][0] = 0.08333333333333333;
	conversionTable[1][1] = 1.0;
	conversionTable[1][2] = 0.00001578282828283;
	conversionTable[1][3] = 25.4;
	conversionTable[1][4] = 0.0254;
	conversionTable[1][5] = 2.54;
}

//set the values for conversions involving miles
void DistanceConverter::setMilesRow(){
	conversionTable[2][0] = 5280.0;
	conversionTable[2][1] = 63360.0;
	conversionTable[2][2] = 1.0;
	conversionTable[2][3] = 1609344.0;
	conversionTable[2][4] = 1609.344;
	conversionTable[2][5] = 16093.44;
}

//set the values for conversions involving millimeters
void DistanceConverter::setMillimetersRow(){
	conversionTable[3][0] = 0.00328083989501310;
	conversionTable[3][1] = 0.03937007874015700;
	conversionTable[3][2] = 0.00000062137119224;
	conversionTable[3][3] = 1.0;
	conversionTable[3][4] = 0.001;
	conversionTable[3][5] = 0.01;
}

//set the values for conversions involving meters
void DistanceConverter::setMetersRow(){
	conversionTable[4][0] = 3.28083989501310000;
	conversionTable[4][1] = 39.3700787401570000;
	conversionTable[4][2] = 0.00062137119223733;
	conversionTable[4][3] = 1000.0;
	conversionTable[4][4] = 1.0;
	conversionTable[4][5] = 100.0;
}

//set the values for conversions involving centimeters
void DistanceConverter::setCentimetersRow(){
	conversionTable[5][0] = 0.03280839895013100;
	conversionTable[5][1] = 0.39370078740157000;
	conversionTable[5][2] = 0.00000621371192237;
	conversionTable[5][3] = 10.0;
	conversionTable[5][4] = 0.01;
	conversionTable[5][5] = 1.0;
}

//sets the values to use for outputing the proper units the user selected
void DistanceConverter::createUnitsString(){
	units[0] = "feet(ft)";
	units[1] = "inches(in)";
	units[2] = "miles(mi)";
	units[3] = "millimeters(mm)";
	units[4] = "meters(m)";
	units[5] = "centimeters(cm)";
}

//converts a distance to the user specified units
void DistanceConverter::run(){
	showMainMenu();
	
	unsigned int convertFrom = getConvertFromToChoice(true);
	unsigned int convertTo = getConvertFromToChoice(false);

	double distanceToConvert = getConvertDistance();

	//print answer
	cout << "\n" << distanceToConvert << " " << units[convertFrom -1].c_str() << " is equal to "
		 << distanceToConvert * conversionTable[convertFrom - 1][convertTo - 1]
		 << " " << units[convertTo - 1].c_str();
}

//checks if the user wants to continue converting distances
bool DistanceConverter::userWantsToRunAgain(){
	cout << "\nCalculate more distance conversions(y/n)? ";

	cin.ignore(1000, '\n');

	//check only the first char
	return (cin.get() == 'y');
}

//ensures the user can keep converting distances until the user wants to quit
void DistanceConverter::start(){
	do{
		run();
	}while(userWantsToRunAgain());
}

//gets the units to convert to and from
unsigned int DistanceConverter::getConvertFromToChoice(bool from){
	//determine which message to show
	if(from)
		cout << "\nWhat units would you like to convert from? ";
	else
		cout << "\nWhat units would you like to convert to? ";

	unsigned int userChoice = 0;

	if(cin.width() != 0) cin.ignore(1000, '\n');

	//input validation
	do{
		cin >> userChoice;

		//invalid input
		if(cin.fail()){
			cin.clear();
			cin.ignore(1000, '\n');
			userChoice = 0;
		}
	//input must be 1 - 6
	}while(userChoice < 1 || userChoice > 6);

	return userChoice;
}

//gets the distance the user wishes to convert
double DistanceConverter::getConvertDistance(){
	cout << "\nEnter the distance you would like to convert: ";

	double distance = 0;

	if(cin.width() != 0) cin.ignore(1000, '\n');

	cin >> distance;

	//invalid input
	if(cin.fail()){
		cin.clear();
		cin.ignore(1000, '\n');
		distance = 0;
	}

	return distance;
}